package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.AlertNotifyDto;
import com.zzyl.entity.AlertData;
import com.zzyl.entity.AlertRule;
import com.zzyl.mapper.AlertDataMapper;
import com.zzyl.mapper.AlertRuleMapper;
import com.zzyl.mapper.NursingElderMapper;
import com.zzyl.mapper.UserRoleMapper;
import com.zzyl.service.AmqpService;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.DeviceDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class AmqpServiceImpl implements AmqpService {
    @Autowired
    AlertRuleMapper alertRuleMapper;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    UserRoleMapper userRoleMapper;

    @Autowired
    NursingElderMapper nursingElderMapper;
    @Autowired
    AlertDataMapper alertDataMapper;
    @Autowired
    private WebSocketServer webSocketServer;

    @Override
    public void checkAlarm(List<DeviceDataVo> deviceDataVos) {
        // 检查某个设备的某个functionId的value是否异常
        for (DeviceDataVo data : deviceDataVos) {
            String productKey = data.getProductKey();
            String iotId = data.getIotId();
            String functionId = data.getFunctionId();
            String dataValue = data.getDataValue();
            LocalDateTime alarmTime = data.getAlarmTime();
            // 获取对应当前数据的告警规则
            List<AlertRule> rules = alertRuleMapper.selectByProductIotIdFucntionId(productKey, iotId, functionId);
            if (CollectionUtils.isEmpty(rules)) {
                continue;
            }
            // 计算是否出现告警
            for (AlertRule rule : rules) {
                // 判断时间，如果不在告警的时间段范围之内，就不处理
                String alertEffectivePeriod = rule.getAlertEffectivePeriod();
                if (StringUtils.isEmpty(alertEffectivePeriod)) {
                    continue;
                }
                String[] arr = rule.getAlertEffectivePeriod().split("~");
                LocalTime startTime = LocalTime.parse(arr[0]);
                LocalTime endTime = LocalTime.parse(arr[1]);
                //上报时间
                LocalTime dataTime = LocalDateTimeUtil.of(alarmTime).toLocalTime();
                if (dataTime.isAfter(startTime) && dataTime.isBefore(endTime)) {
                    // 找到一条报警规则规则
                    if (Objects.equals(rule.getOperator(), ">=") && Float.parseFloat(dataValue) >= rule.getValue()) {
                        log.info(JSONUtil.toJsonStr(rule));
                        parepareAlert(data, rule);
                    }
                    if (Objects.equals(rule.getOperator(), "<=") && Float.parseFloat(dataValue) <= rule.getValue()) {
                        log.info(JSONUtil.toJsonStr(rule));

                        parepareAlert(data, rule);
                    }
                }
            }
        }
    }

    private void parepareAlert(DeviceDataVo data, AlertRule rule) {
        // 持续周期
        Integer duration = rule.getDuration();
        // 读取redis中的旧的持续周期值
        String durationKey = CacheConstants.IOT_DEVICE_ALERT_DURATION + data.getIotId() + ":" + data.getFunctionId() + ":" + rule.getId();
        // 把旧的持续周期+1
            Long increment = redisTemplate.opsForValue().increment(durationKey);
        // 设置过期时间，不要超过2个持续周期
        redisTemplate.expire(durationKey, 8, TimeUnit.SECONDS);
        // 到达持续周期
        if (increment != null && increment >= duration) {
            // 获取静默周期的key
            String silentKey = CacheConstants.IOT_DEVICE_ALERT_SILENT + data.getIotId() + ":" + data.getFunctionId() + ":" + rule.getId();
            Boolean exists = redisTemplate.hasKey(silentKey);
            if (exists != null && exists) {
                // 处于静默周期
                log.info(" 处于静默周期");
            } else {
                // 发告警
                // 设置静默周期
                Integer alertSilentPeriod = rule.getAlertSilentPeriod();
                redisTemplate.opsForValue().set(silentKey, "silent", alertSilentPeriod, TimeUnit.MINUTES);
         /*       // 清零持续周期
                redisTemplate.delete(durationKey);*/
                // 保存告警数据，发短信，打电话。

                ArrayList<Long> userIds = warning(data, rule);
                if (CollectionUtils.isEmpty(userIds)) {
                    log.error("没有找到告警接收人，data：{}，rule：{} ", data, rule);
                    return;
                }
                // 保存到数据库
                List<AlertData> alertDataList = new ArrayList<AlertData>();
                for (Long userId : userIds) {
                    AlertData alertData = BeanUtil.copyProperties(data, AlertData.class);
                    alertData.setAlertRuleId(rule.getId());
                    String alertReason = CharSequenceUtil.format("{}{}{},持续{}个周期就报警", rule.getFunctionName(), rule.getOperator(), rule.getValue(), rule.getDuration());
                    alertData.setAlertReason(alertReason);
                    alertData.setType(rule.getAlertDataType());
                    alertData.setStatus(0);
                    alertData.setUserId(userId);
                    alertDataList.add(alertData);
                }
                alertDataMapper.batchInsert(alertDataList);

            }
        } else {
            log.info("没有达持续周期");
        }
    }

    private ArrayList<Long> warning(DeviceDataVo data, AlertRule rule) {

        Set<Long> ids = new HashSet<>();
        if (data.getLocationType() == 0) {
            //如果是随身设备
            List<Long> nursingIds = nursingElderMapper.selectByIotIdElderId(data.getIotId());
            ids.addAll(nursingIds);
        } else if (data.getLocationType() == 1 && data.getPhysicalLocationType() == 2) {
            //如果是固定床上的设备
            List<Long> nursingIds = nursingElderMapper.selectByIotIdBedIdElderId(data.getIotId());
            ids.addAll(nursingIds);
        } else {
            //如果是固定设备
            //给维修工和管理员发消息
            List<Long> uIds = userRoleMapper.selectByRoleName("维修工");
            ids.addAll(uIds);
        }
        List<Long> uIds = userRoleMapper.selectByRoleName("超级管理员");
        ids.addAll(uIds);
        return new ArrayList<>(uIds);
    }

    /**
     * 发送websocket通知
     *
     * @param alertRule 报警规则
     * @param alertData 报警数据
     */
    private void websocketNotify(AlertRule alertRule, AlertData alertData, List<Long> userIds) {
        // websocket通知：弹窗消息
        AlertNotifyDto alertNotifyDto = BeanUtil.toBean(alertData, AlertNotifyDto.class);
        alertNotifyDto.setFunctionName(alertRule.getFunctionName());
        alertNotifyDto.setAlertDataType(alertData.getType());
        alertNotifyDto.setNotifyType(1);
        //给指定消费者发送消息
        webSocketServer.sendMessageToConsumer(alertNotifyDto, userIds);
    }
}






